/**
 * @export
 * @class AimPulse
 * @classdesc 目标标记动画类
 * @property {Object} 地图容器 - SchoolLab实例
 * @property {String} name - 名称
 * @property {String} color - 颜色
 * @property {Number} opacity - 透明度
 * @property {Number} radius - 半径
 * @property {Number} renderOrder - 层叠顺序
 * @example
 * var pulse = new AimPulse(viewer, {
 *   radius: 4,
 *   color: '#ff0000',
 *   opacity: 0.5,
 *   renderOrder: 20,
 *   name: 'aimPulse1'
 * })
 */
import { extend, lngLatToWorld, transformCoordinate } from './util'
import { TimelineLite, Linear } from 'gsap'
import Feature from './Feature'
export default class AimPulse {
  constructor(viewer, options) {
    const opts = extend({
      name: "aimPulse",
      color: "#ffffff",
      opacity: 1,
      radius: 1,
      renderOrder: 1
    }, options)

    /** @member {SchoolLab} - 地图容器 */
    this.viewer = viewer
    
    /** @member {String} - 名称 */
    this.name = opts.name
    
    /** @member {Color} - 颜色 */
    this.color = opts.color
    
    /** @member {Number} - 透明度 */
    this.opacity = opts.opacity
    
    /** @member {Number} - 半径 */
    this.radius = opts.radius
    
    /** @member {Number} - 层叠顺序 */
    this.renderOrder = opts.renderOrder
    
    /** @member {THREE.Mesh} - mesh对象 */
    this.entity = null

    Feature.apply(this)

    this._init()
  }

  _init() {
    this.viewer.animationManager.regist('aimPulse', this._update.bind(this))
    let geometry = this._initGeometry()
    let material = this._initMaterial()

    const mesh = new THREE.Mesh(geometry, material)
    mesh.name = this.name
    mesh.renderOrder = this.renderOrder
    mesh.scale.set(0.0001, 0.0001, 1)

    this.entity = mesh
    this.viewer.world.add(mesh)
  }

  _initGeometry() {
    const geometry = new THREE.PlaneBufferGeometry(this.radius, this.radius, 2)
    return geometry
  }

  _initMaterial() {
    const uniforms = {
      time: { type: "f", value: 0 },
      color: { type: "c", value: new THREE.Color(this.color) },
      opacity: { type: "f", value: this.opacity }
    }

    let vs = this._initVS()
    let fs = this._initFS()
    const material = new THREE.ShaderMaterial({
      uniforms: uniforms,
      vertexShader: vs,
      fragmentShader: fs,
      blending: THREE.AdditiveBlending,
      transparent: true,
      depthWrite: false,
      depthTest: true,
      side: THREE.DoubleSide
    })

    return material
  }

  _initVS() {
    const vs = `
      precision lowp float;
      precision lowp int;
      
      varying vec2 vUv;
      void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
      }
    `
    return vs
  }

  _initFS() {
    const fs = `
      precision lowp float;
      precision lowp int;
      varying vec2 vUv;
      uniform float time;
      uniform vec3 color;
      uniform float opacity;
      
      float sections = 3.0;
      const float PI = 3.14159265;
      
      bool belongs(float time, vec2 uv, float near, float far) {
        near += sin(uv.x - time * 8.0) / 50.0;
        far += cos(uv.y - time * 8.0) / 50.0;
        vec2 center = vec2(0.5, 0.5);
        vec2 xy = uv - center;
        float dist = distance(xy, vec2(0.0, 0.0));
        float angle = mod(atan(xy.y, xy.x) + time * 2.5 + sin(time * 4.0) / 1.0, PI * 2.0);
        float oddity = mod(angle / (2.0 * PI) * sections * 2.0, 2.0);
        if (dist > near && dist < far && floor(mod(oddity, 2.0)) == 0.0) {
            return true;
        } else {
            return false;
        }
      }
      
      void main() {
        vec2 uv = vUv;
      
        if (belongs(time, uv, 0.2, 0.25) || belongs(time + 0.5, uv, 0.3, 0.35) || belongs(time + 1.0, uv, 0.4, 0.45)) {
          gl_FragColor = vec4(color, opacity);
        } else {
          gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
        }
      }
    `
    return fs
  }

  _update() {
    this.entity.material.uniforms.time.value += 0.01
  }

  // 设置经纬度坐标位置
  setGisPosition(lngLat, altitude) {
    this.entity.visible = false
    let world = lngLatToWorld(lngLat)
    let format = transformCoordinate(this.viewer.gisCenter, world)
    this.entity.position.set(format.x, format.y, altitude)
    this.entity.visible = true
  }

  // 设置世界坐标位置
  setPosition(vec2, altitude) {
    this.entity.visible = false
    this.entity.position.set(vec2.x, vec2.y, altitude)
    this.entity.visible = true
  }

  // 对象显示
  show(callback, ...args) {
    let self = this
    let tl = new TimelineLite({
      paused: !1,
      delay: 0,
      repeat: 0,
      yoyo: true,
      onComplete: function() {
        tl = null
        // args[0]: floor, args[1]: path, args[2]: centerPos args[3]: radius args[4]: buildingData
        callback(args[0], args[1], args[2], args[3], args[4])
      },
      onUpdate: function() {
        self.entity.scale.set(scale.x, scale.y, 1)
      }
    })
    let scale = {
      x: 0.0001,
      y: 0.0001
    }

    tl.to(scale, 0.5, {
      x: 1,
      y: 1,
      ease: Linear.none
    }, 0)
  }

  // 对象隐藏
  hide() {
    let self = this
    let tl = new TimelineLite({
      paused: !1,
      delay: 0,
      repeat: 0,
      yoyo: true,
      onComplete: function() {
        tl = null
      },
      onUpdate: function() {
        self.entity.scale.set(scale.x, scale.y, 1)
      }
    })
    let scale = {
      x: 1,
      y: 1
    }

    tl.to(scale, 0.5, {
      x: 0.0001,
      y: 0.0001,
      ease: Linear.none
    }, 0)
  }

  // 对象销毁
  destroy() {
    this.viewer.animationManager.unload('aimPulse')
    this._disposeHierarchy(this.entity, this._dispose)
    this.viewer.world.remove(this.entity)
    this.entity = null
  }
}
